# coding=utf-8
import json
import re

from jsonpath import jsonpath
from api.FlowInstance.approve_process import Approve_Process

# 用于组装复杂请求体的方法封装
class Request_Body(Approve_Process):

    # 解析表决参数
    def vote_param(self,approve_params, approve_body, **kwargs):
        if approve_params['action'][0].lower() == '表决':
            vote_params = approve_params['action'][1]
            # 更新抄送人
            self.update_cc_list_to_body_by_operate(approve_params,approve_body)
            for k, v in vote_params.items():
                # 输入表决意见
                if k.lower() == 'handtext':
                    approve_body.update({"opinion":v})
                # 表决是否同意
                elif k.lower() == 'vote':
                    if v == '不同意':
                        approve_body.update({"voted_status": "2"})
                    else:
                        approve_body.update({"voted_status": "1"})
                # 选择审批组织
                elif k.lower() == 'approvedepartrole':
                    resp = kwargs['user_orgs_resp']
                    # 如果在响应能找到入参传入的组织，则进行update
                    self.update_org_info(approve_body,resp,v)
                else:
                    assert False,f'参数【{k}】不存在，请调整yml中传入param的参数!'
        return approve_body

    # 解析审批同意参数
    def pass_param(self,approve_params, approve_body, **kwargs):
        if approve_params['action'][0].lower() in ['同意','归档']:
            pass_params = approve_params['action'][1]
            tplData = kwargs['tplData']
            # 更新抄送人
            self.update_cc_list_to_body_by_operate(approve_params,approve_body)
            # 默认归档目录
            if approve_params['action'][0] == '归档':
                # 如果已经设置过归档目录，则使用自动归档目录
                SaveFolderGuid = self.jsonpath_value(tplData,'$..SaveFolderGuid')
                if SaveFolderGuid !='':
                    approve_body.update({'archived_directory_id': SaveFolderGuid})
                # 否则随机使用一个默认归档目录
                else:
                    SaveFolderGuid = self.jsonpath_value(tplData,
                                                        f'$.DefaultApproveGuide.SaveFolder.SaveFolderList[0].id')
                    approve_body.update({'archived_directory_id': SaveFolderGuid})
            for k, v in pass_params.items():
                # 更新意见
                if k.lower() == 'handtext':
                    approve_body.update({"opinion": v})
                # 设置归档目录
                elif k.lower() == 'savefolder':
                    if jsonpath(tplData, f'$..SaveFolderList[?(@.text=="{v}")]'):
                        savefolder_id = self.jsonpath_value(tplData, f'$.DefaultApproveGuide.SaveFolder.SaveFolderList[?(@.text=="{v}")].id')
                        approve_body.update({'archived_directory_id':savefolder_id})
                    else:
                        assert False, f'归档目录：【{v}】不存在，请修改调整yml的【{k}】值'
                # 选择审批组织
                elif k.lower() == 'approvedepartrole':
                    resp = kwargs['user_orgs_resp']
                    self.update_org_info(approve_body,resp,v)
                else:
                    assert False,f'参数【{k}】不存在，请调整yml中传入param的参数!'
            return approve_body

    # 解析驳回入参
    def rollback_param(self,approve_params, approve_body, **kwargs):
        # 把审批同意的入参改造后，组成驳回的入参
        approve_body.pop('actuals')
        approve_body.pop('branch_choose')
        approve_body.pop('archived_directory_id')
        approve_body.pop('_prc_name_')
        approve_body.update({'only_do_validate':False})
        initiater = approve_body['initiater']
        # 新增默认审批组织信息,驳回使用的是station
        station = {'station_guid': initiater['initiater_org_id'], 'station_name': initiater['initiater_org_name']}
        approve_body.update(station=station)
        # 改造initiater，去掉initiater_org_id，initiater_org_name
        initiater.pop('initiater_org_id')
        initiater.pop('initiater_org_name')
        approve_body.update(initiater=initiater)

        # 更新抄送人
        self.update_cc_list_to_body_by_operate(approve_params,approve_body)

        rollback_params = approve_params['action'][1]
        for k, v in rollback_params.items():
            # 更新意见
            if k.lower() == 'handtext':
                approve_body.update({"opinion": v})
            elif k.lower() == 'rollbackto':
                node_id = self.jsonpath_value(approve_body, '$.node_id')
                # 获取可打回步骤的信息
                csrf_token = kwargs['csrf_token']
                reject_step_resp = self.can_reject_steps(node_id,csrf_token)
                resp_json = json.loads(reject_step_resp.text)
                # 判断输入的要打回步骤是否存在
                if v == '发起':
                    approve_body.update({"step_id": 'new_start'})
                elif v == '上一步':
                    # 取响应data的最后一个步骤组的step_define_id
                    step_define_id = jsonpath(resp_json, '$.data[-1:].step_define_id')[0]
                    approve_body.update({"step_id": step_define_id})
                elif jsonpath(resp_json, f'$.data[?(@.name=="{v}")].step_define_id'):
                    step_define_id = self.jsonpath_value(resp_json, f'$.data[?(@.name=="{v}")].step_define_id')
                    approve_body.update({"step_id": step_define_id})
                else:
                    assert False, (f'参数【{k}】不存在【{v}】步骤')
            # 打回重走或不重走
            elif k.lower() == 'rollbacktype':
                if v == '重走':
                    approve_body.update({'roll_back_type': '1'})
                else:
                    approve_body.update({'roll_back_type': '0'})
            # 选择审批组织
            elif k.lower() == 'approvedepartrole':
                station = {}
                resp = kwargs['user_orgs_resp']
                resp_json = json.loads(resp.text)
                # 如果在响应能找到入参传入的组织，则进行update
                if jsonpath(resp_json, f'$.data.departData[?(@.name_path=="{v}")].org_id'):
                    org_id = self.jsonpath_value(resp_json, f'$.data.departData[?(@.name_path=="{v}")].org_id')
                    name_path = self.jsonpath_value(resp_json,
                                                    f'$.data.departData[?(@.name_path=="{v}")].name_path')
                    station.update({'station_guid':org_id,'station_name':name_path})
                    approve_body.update(station=station)
                else:
                    assert False, (f'参数【{k}】不存在【{v}】组织')
            else:
                assert False, (f'参数【{k}】不存在，请调整yml中传入param的参数!')
        return approve_body

    def consult_param(self,approve_params, approve_body, **kwargs):
        # 把审批同意的入参改造后，组成协商的入参
        approve_body.pop('step_cc_list')
        approve_body.pop('actuals')
        approve_body.pop('branch_choose')
        approve_body.pop('archived_directory_id')
        approve_body.pop('manual_execution')
        approve_body.pop('_prc_name_')
        consult_params = approve_params['action'][1]
        to = []
        for k, v in consult_params.items():
            # 更新协商意见
            if k.lower() == 'handtext':
                approve_body.update({"opinion": v})
            # 选择协商人,此处consultto是list，因为协商人可以是多个
            elif k.lower() == 'consultto':
                for name in v:
                    auditor_info: dict = self.get_auditor_dict_by_user(name)
                    if auditor_info:
                        to.append(auditor_info)
                    else:
                        assert False, f'协商人【{name}】不存在'
                # 更新传阅用户的列表信息
                approve_body.update(to=to)
            else:
                assert False, f'参数【{k}】不存在，请调整yml中传入param的参数!'
        return approve_body

    def update_cc_list_to_body_by_operate(self,approve_params,approve_body:dict):
        """
        通过yml的操作，更新请求体的抄送人列表信息
        :param approve_params: 用到yml参数中的的action，step_cc_list
        :param approve_body: 基础请求体，base_body
        :return: approve_body 返回更新抄送信息后的请求体
        """
        cc_list = self.get_cc_list_by_name(approve_params)  # 如果approve_params中没有抄送人，cc_list为空列表
        operate = approve_params['action'][0]
        if operate == '交办' or operate == '终止': # 在识别到的操作中，交办，终止请求体的抄送是cc_list
            approve_body.setdefault('cc_list',approve_body['step_cc_list']) #设置cc_list，值默认是step_cc_list
            approve_body.pop('step_cc_list')
            approve_body['cc_list'].extend(cc_list)
        else:
            # 更新其他操作请求体的抄送人通过,extend追加进抄送人
            approve_body['step_cc_list'].extend(cc_list)
        return approve_body

    def assigned_param(self,approve_params, approve_body, **kwargs):
        # 把审批同意的入参改造后，组成交办的入参
        approve_body.pop('actuals')
        approve_body.pop('branch_choose')
        approve_body.pop('archived_directory_id')
        approve_body.pop('manual_execution')
        approve_body.pop('_prc_name_')
        # # 更新抄送人
        self.update_cc_list_to_body_by_operate(approve_params,approve_body)
        assigned_params = approve_params['action'][1]
        assigned = []
        for k, v in assigned_params.items():
            # 更新协商意见
            if k.lower() == 'handtext':
                approve_body.update({"opinion": v})
            elif k.lower() == 'approvedepartrole':
                resp = kwargs['user_orgs_resp']
                # 如果在响应能找到入参传入的组织，则进行update
                self.update_org_info(approve_body,resp,v)
            # 选择交办人
            elif k.lower() == 'assignedto':
                auditor_info: dict = self.get_auditor_dict_by_user(v)
                if auditor_info:
                    assigned.append(auditor_info)
                else:
                    assert False, f'交办人【{v}】不存在'
                # 更新传阅用户的列表信息
                approve_body.update(assigned=assigned)
            else:
                assert False, f'参数【{k}】不存在，请调整yml中传入param的参数!'
        return approve_body

    def cancel_param(self,approve_params, approve_body, **kwargs):
        # 把审批同意的入参改造后，组成作废和终止的入参，两个接口的入参基本一致
        approve_body.pop('actuals')
        approve_body.pop('branch_choose')
        approve_body.pop('archived_directory_id')
        approve_body.pop('_prc_name_')
        approve_body.update({'only_do_validate':False})
        # 终止的抄送列表是cc_list
        self.update_cc_list_to_body_by_operate(approve_params,approve_body)
        cancel_params = approve_params['action'][1]
        for k, v in cancel_params.items():
            # 更新处理意见
            if k.lower() == 'handtext':
                approve_body.update({"opinion": v})
            elif k.lower() == 'approvedepartrole':
                resp = kwargs['user_orgs_resp']
                # 如果在响应能找到入参传入的组织，则进行update
                self.update_org_info(approve_body,resp,v)
            else:
                assert False,(f'参数【{k}】不存在，请调整yml中传入param的参数!')
        return approve_body

    def update_org_info(self,approve_body,user_orgs_resp,name_path):
        """
        更新yml中传入的组织信息到请求体中
        :param approve_body: 基础请求体
        :param user_orgs_resp: 获取用户组织的响应(/flowinstance/process/ajax-get-user-orgs)
        :param name_path: yml中的组织名
        :return:
        """
        resp_json = json.loads(user_orgs_resp.text)
        # 如果在响应能找到入参传入的组织，则进行update
        if jsonpath(resp_json, f'$.data.departData[?(@.name_path=="{name_path}")].org_id'):
            org_id = self.jsonpath_value(resp_json, f'$.data.departData[?(@.name_path=="{name_path}")].org_id')
            name = self.jsonpath_value(resp_json,
                                            f'$.data.departData[?(@.name_path=="{name_path}")].name_path')
            approve_body['initiater']['initiater_org_id'] = org_id
            approve_body['initiater']['initiater_org_name'] = name
        else:
            assert False,f'责任人【{approve_body["initiater"]["initiater_name"]}】组织【{name_path}】不存在'

    def get_auditor_dict_by_user(self,name):
        """
        通过用户姓名，组装用户信息字典,用于责任人选择，比如协商人，交办人,加签人。返回字典
        :param name: 用户姓名或者用户code均可
        :return: 字典
        """
        auditor_info = {}
        resp = self.get_users_by_name(name)
        resp_json = json.loads(resp.text)
        # 判断响应是否存在需要的人，
        jp_expr = f'$.data.data[?(@.name=="{name}" || @.code=="{name}")]'
        if jsonpath(resp_json, jp_expr):
            auditor_name = self.jsonpath_value(resp_json, f'{jp_expr}.name')
            auditor_id = self.jsonpath_value(resp_json, f'{jp_expr}.id')
            auditor_code = self.jsonpath_value(resp_json, f'{jp_expr}.code')
            station_name = self.jsonpath_value(resp_json,
                                               f'{jp_expr}.org_settings[?(@.is_default in [1,"1"])].name_path')
            station_guid = self.jsonpath_value(resp_json,
                                               f'{jp_expr}.org_settings[?(@.is_default in [1,"1"])].org_id')
            # 用户信息组成json
            auditor_info.update(
                {'auditor_name': auditor_name, 'auditor_id': auditor_id, 'auditor_code': auditor_code,
                 'station_name': station_name, 'station_guid': station_guid})
            return auditor_info
        else:
            return auditor_info

    def add_sign_param(self,approve_params, approve_body, **kwargs):
        # 把审批同意的入参改造后，组成需要的入参
        approve_body.pop('step_cc_list')
        approve_body.pop('actuals')
        approve_body.pop('branch_choose')
        approve_body.pop('archived_directory_id')
        approve_body.pop('manual_execution')
        approve_body.pop('_prc_name_')
        add_sign_params = approve_params['action'][1]
        add_sign_users = []
        for k, v in add_sign_params.items():
            # 更新意见
            if k.lower() == 'handtext':
                approve_body.update({"opinion": v})
            elif k.lower() == 'addsignafter':
                if '再次确认' in v:
                    approve_body.update({"add_sign_after": '0'})
                elif '下一步' in v:
                    approve_body.update({"add_sign_after": '1'})
                else:
                    assert False, (f'加签后操作方式【{v}】不存在')
            # 选择加签人,此处addsignto是list，因为加签人可以是多个
            elif k.lower() == 'addsignto':
                for name in v:
                    auditor_info:dict = self.get_auditor_dict_by_user(name)
                    if auditor_info:
                        add_sign_users.append(auditor_info)
                    else:
                        assert False, f'加签人【{name}】不存在'
                # 更新加签用户的列表信息
                approve_body.update(add_sign_users=add_sign_users)
            else:
                assert False,f'参数【{k}】不存在，请调整yml中传入param的参数!'
        return approve_body

